package com.mkx.core.auto;

import com.mkx.core.monitor.SystemLoadMonitor;
import com.mkx.properties.RedisLockProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 自动配置优化器
 * 根据系统负载和Redis性能指标自动调整锁配置参数
 */
public class AutoConfigOptimizer {

    private static final Logger logger = LoggerFactory.getLogger(AutoConfigOptimizer.class);
    private static final AutoConfigOptimizer INSTANCE = new AutoConfigOptimizer();
    
    private final SystemLoadMonitor loadMonitor;
    private final ScheduledExecutorService scheduler;
    private RedisLockProperties properties;
    private RedisTemplate<String, Object> redisTemplate;
    private boolean autoOptimizationEnabled;
    
    // 配置参数的调整范围限制
    private static final double MAX_EXPIRE_TIME_FACTOR = 2.0;
    private static final double MIN_EXPIRE_TIME_FACTOR = 0.5;
    private static final double MAX_RETRY_INTERVAL_FACTOR = 3.0;
    private static final double MIN_RETRY_INTERVAL_FACTOR = 0.3;
    
    // 配置基准值（用于恢复默认值）
    private long baseExpireTime;
    private long baseRetryInterval;
    private long baseWaitTime;
    
    private AutoConfigOptimizer() {
        this.loadMonitor = SystemLoadMonitor.getInstance();
        this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "auto-config-optimizer");
            t.setDaemon(true);
            return t;
        });
        this.autoOptimizationEnabled = false;
    }
    
    /**
     * 获取单例实例
     */
    public static AutoConfigOptimizer getInstance() {
        return INSTANCE;
    }
    
    /**
     * 初始化优化器
     */
    public void initialize(RedisLockProperties properties, RedisTemplate<String, Object> redisTemplate) {
        this.properties = properties;
        this.redisTemplate = redisTemplate;
        
        // 保存基准配置值
        this.baseExpireTime = properties.getExpireTime();
        this.baseRetryInterval = properties.getRetryInterval();
        this.baseWaitTime = properties.getWaitTime();
        
        // 自动启用优化
        this.autoOptimizationEnabled = true;
        
        // 启动优化线程，每30秒执行一次配置优化
        scheduler.scheduleAtFixedRate(this::optimizeConfig, 0, 30, TimeUnit.SECONDS);
        
        logger.info("Auto config optimizer initialized and enabled");
        
        // 添加JVM关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            scheduler.shutdown();
            try {
                scheduler.awaitTermination(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }));
    }
    
    /**
     * 优化配置参数
     */
    private void optimizeConfig() {
        if (!autoOptimizationEnabled || properties == null) {
            return;
        }
        
        try {
            SystemLoadMonitor.SystemLoad load = loadMonitor.getCurrentLoad();
            SystemLoadMonitor.LoadLevel loadLevel = loadMonitor.getLoadLevel();
            
            // 根据负载等级调整参数
            switch (loadLevel) {
                case HIGH:
                    optimizeForHighLoad();
                    break;
                case MEDIUM:
                    optimizeForMediumLoad();
                    break;
                case LOW:
                    optimizeForLowLoad();
                    break;
            }
            
            logger.debug("Auto config optimized for {} load - CPU: {:.2f}%, Memory: {:.2f}%, Threads: {}",
                    loadLevel, load.cpuUsage * 100, load.memoryUsage * 100, load.threadCount);
            
        } catch (Exception e) {
            logger.warn("Failed to optimize configuration", e);
        }
    }
    
    /**
     * 高负载优化策略
     * 目标：减少系统压力，防止资源耗尽
     */
    private void optimizeForHighLoad() {
        // 增加锁过期时间，减少续期频率
        long newExpireTime = (long) (baseExpireTime * MAX_EXPIRE_TIME_FACTOR);
        properties.setExpireTime(newExpireTime);
        
        // 增加重试间隔，减少竞争频率
        long newRetryInterval = (long) (baseRetryInterval * MAX_RETRY_INTERVAL_FACTOR);
        properties.setRetryInterval(newRetryInterval);
        
        // 减少等待时间，快速失败
        long newWaitTime = (long) (baseWaitTime * MIN_EXPIRE_TIME_FACTOR);
        properties.setWaitTime(newWaitTime);
        
        // 在高负载下，可以考虑临时禁用机器学习预测以减少计算开销
        if (loadMonitor.getAverageCpuUsage() > 0.85) {
            properties.setMlPredictionEnabled(false);
            logger.info("Temporarily disabled ML prediction due to extremely high system load");
        }
        
        logger.debug("High load optimization applied: expireTime={}ms, retryInterval={}ms, waitTime={}ms",
                newExpireTime, newRetryInterval, newWaitTime);
    }
    
    /**
     * 中等负载优化策略
     * 目标：平衡性能和资源使用
     */
    private void optimizeForMediumLoad() {
        // 略微增加锁过期时间
        long newExpireTime = (long) (baseExpireTime * 1.2);
        properties.setExpireTime(newExpireTime);
        
        // 略微增加重试间隔
        long newRetryInterval = (long) (baseRetryInterval * 1.5);
        properties.setRetryInterval(newRetryInterval);
        
        // 恢复等待时间为默认值
        properties.setWaitTime(baseWaitTime);
        
        // 确保启用机器学习预测以优化重试策略
        properties.setMlPredictionEnabled(true);
        
        logger.debug("Medium load optimization applied: expireTime={}ms, retryInterval={}ms, waitTime={}ms",
                newExpireTime, newRetryInterval, baseWaitTime);
    }
    
    /**
     * 低负载优化策略
     * 目标：最大化性能和响应速度
     */
    private void optimizeForLowLoad() {
        // 恢复默认锁过期时间
        properties.setExpireTime(baseExpireTime);
        
        // 使用较小的重试间隔，加快获取锁的速度
        long newRetryInterval = (long) (baseRetryInterval * MIN_RETRY_INTERVAL_FACTOR);
        properties.setRetryInterval(newRetryInterval);
        
        // 增加等待时间，提高锁获取成功率
        long newWaitTime = (long) (baseWaitTime * 1.5);
        properties.setWaitTime(newWaitTime);
        
        // 确保启用自适应重试和机器学习预测
        properties.setAdaptiveRetryEnabled(true);
        properties.setMlPredictionEnabled(true);
        
        logger.debug("Low load optimization applied: expireTime={}ms, retryInterval={}ms, waitTime={}ms",
                baseExpireTime, newRetryInterval, newWaitTime);
    }
    
    /**
     * 启用自动优化
     */
    public void enableAutoOptimization() {
        this.autoOptimizationEnabled = true;
        logger.info("Auto configuration optimization enabled");
    }
    
    /**
     * 禁用自动优化
     */
    public void disableAutoOptimization() {
        this.autoOptimizationEnabled = false;
        // 恢复默认配置
        if (properties != null) {
            properties.setExpireTime(baseExpireTime);
            properties.setRetryInterval(baseRetryInterval);
            properties.setWaitTime(baseWaitTime);
        }
        logger.info("Auto configuration optimization disabled, restored default values");
    }
    
    /**
     * 手动触发配置优化
     */
    public void triggerOptimization() {
        optimizeConfig();
    }
    
    /**
     * 获取当前配置信息
     */
    public ConfigSnapshot getCurrentConfig() {
        if (properties == null) {
            return null;
        }
        
        return new ConfigSnapshot(
                properties.getExpireTime(),
                properties.getRetryInterval(),
                properties.getWaitTime(),
                properties.isAdaptiveRetryEnabled(),
                properties.isMlPredictionEnabled(),
                autoOptimizationEnabled
        );
    }
    
    /**
     * 配置快照类
     */
    public static class ConfigSnapshot {
        public final long expireTime;
        public final long retryInterval;
        public final long waitTime;
        public final boolean adaptiveRetryEnabled;
        public final boolean mlPredictionEnabled;
        public final boolean autoOptimizationEnabled;
        
        public ConfigSnapshot(long expireTime, long retryInterval, long waitTime,
                             boolean adaptiveRetryEnabled, boolean mlPredictionEnabled,
                             boolean autoOptimizationEnabled) {
            this.expireTime = expireTime;
            this.retryInterval = retryInterval;
            this.waitTime = waitTime;
            this.adaptiveRetryEnabled = adaptiveRetryEnabled;
            this.mlPredictionEnabled = mlPredictionEnabled;
            this.autoOptimizationEnabled = autoOptimizationEnabled;
        }
        
        @Override
        public String toString() {
            return String.format("ConfigSnapshot{expireTime=%dms, retryInterval=%dms, waitTime=%dms, " +
                    "adaptiveRetry=%s, mlPrediction=%s, autoOptimization=%s}",
                    expireTime, retryInterval, waitTime, adaptiveRetryEnabled, 
                    mlPredictionEnabled, autoOptimizationEnabled);
        }
    }
}